#pragma once

#include <typeinfo>
#include <typeindex>
#include <memory>
#include <iostream>
#include <assert.h>

#include "IComponent.h"

namespace ZeEngine
{
	class IComponent;

	class Entity
	{
		friend class EntityManager;
		friend class EntityDataStore;

	public:
		IComponent* AddComponent(std::unique_ptr<IComponent> pComponent);
		void RemoveComponent(IComponent& component);
		void RemoveAllComponents();

		u64  GetID() const;
		const std::string& GetName() const;

		template <typename T>
		T* GetComponent() const
		{			
			if (T::m_index >= 0)
			{	
				return static_cast<T*>(m_components[T::m_index].get());
			}

			return nullptr;
		}

		template <typename T>
		bool HasComponent() const
		{
			if (T::m_index >= 0)
			{
				return m_attachedComponents && T::m_type;
			}

			return false;
		}

		bool SupportsAllComponents(u64 componentMask) const;
		bool SupportsAtLeastOneComponent(u64 componentMask) const;
        bool IsActive() const { return m_fActive; }

		void SetActive(bool fActive = true);
        void SetToBeRemoved() { m_fRemove = true; SetActive(false); }

		void Clear(const std::string& name);

	private:
		Entity(const std::string& name);
		virtual ~Entity();

        //private id in the EntityDataStore
        s32 GetIndex() { return m_index; }
        void SetIndex(s32 index) { m_index = index; }

	private:
		std::vector<std::unique_ptr<IComponent>> m_components;

		u64           m_attachedComponents;

		u64           m_id;
		std::string   m_name;
        s32           m_index;

		static u64    m_currentID;

		bool          m_fActive;
        bool          m_fRemove;
	};
}

